package com.mht2017.common.db;

import java.beans.PropertyVetoException;
import java.sql.SQLException;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import com.mht2017.common.dto.IncSyncCheckPoolDto;
import com.mht2017.common.utils.DBUtil;
import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.mchange.v2.c3p0.ComboPooledDataSource;
import com.mchange.v2.c3p0.PooledDataSource;

/**
 * 数据源连接池<br/>
 * 适应多个不同的数据源，每一个数据源将创建一个连接池
 *
 * @author yutong.xiao
 */
public class DBConnectionPool {

	private static final Logger LOGGER = LoggerFactory.getLogger(DBConnectionPool.class);
	/** 创建连接池的锁 **/
	private static final Object createPoolLock = new Object();
	private static final Map<DataSource, PooledDataSource> POOLED_DATA_SOURCES = new HashMap<>();

	public PooledDataSource getPool(DataSource dataSource, IncSyncCheckPoolDto poolDto) throws PropertyVetoException {
		String action = "获取数据源连接池";
		PooledDataSource pool = POOLED_DATA_SOURCES.get(dataSource);
		if (null == pool) {
			LOGGER.debug(String.format("%s-缓存中没有，则创建: '%s'", action, dataSource));
			synchronized (createPoolLock) {
				LOGGER.debug(String.format("%s-创建连接池-获取到锁: '%s'", action, createPoolLock));
				if (null == (pool = POOLED_DATA_SOURCES.get(dataSource))) {
					POOLED_DATA_SOURCES.put(dataSource, pool = newPool(dataSource, poolDto));
					LOGGER.debug(String.format("%s-创建连接池-完成: '%s'", action, pool));
				} else {
					LOGGER.debug(String.format("%s-获取到锁之后再次从缓存中读取，发现已经存在了，则本次创建取消", action));
				}
			}
		}
		return pool;
	}

	public void touchPool(DataSource dataSource, IncSyncCheckPoolDto poolDto) {
		try {
			getPool(dataSource, poolDto);
		} catch (PropertyVetoException e) {
			LOGGER.error("触摸连接池出错", e);
		}
	}

	private ComboPooledDataSource newPool(DataSource dataSource, IncSyncCheckPoolDto poolDto) throws PropertyVetoException {
		ComboPooledDataSource pool = new ComboPooledDataSource();
		pool.setDriverClass(DBUtil.getDriverName(dataSource.getType()));
		pool.setJdbcUrl(DBUtil.getUrl(dataSource));
		pool.setUser(dataSource.getUsername());
		pool.setPassword(dataSource.getPassword());

		// 初始化连接池中的连接数，取值应在minPoolSize与maxPoolSize之间，默认值：3
		pool.setInitialPoolSize(poolDto.getDB_POOL_INITIAL_POOL_SIZE());
		// 连接池中保留的最小连接数，默认值：3
		pool.setMinPoolSize(poolDto.getDB_POOL_MIN_POOL_SIZE());
		// 连接池中保留的最大连接数。默认值: 15
		pool.setMaxPoolSize(poolDto.getDB_POOL_MAX_POOL_SIZE());
		// 最大片段(语句)数量。默认值: 0
		pool.setMaxStatements(poolDto.getDB_POOL_MAX_STATEMENTS());
		// 最大空闲时间，单位：秒。若为0则永不丢弃。默认值: 0
		pool.setMaxIdleTime(poolDto.getDB_POOL_MAX_IDLE_TIME());
		// 当连接池中的连接耗尽的时候c3p0一次同时获取的连接数。默认值: 3
		pool.setAcquireIncrement(1);

		return pool;
	}

	public void clearPool() {
		Collection<PooledDataSource> pools = POOLED_DATA_SOURCES.values();
		if (CollectionUtils.isEmpty(pools)) {
			return;
		}

		for (PooledDataSource pool : pools) {
			try {
				pool.close();
			} catch (SQLException ignore) {
			}
		}
	}

}
